package tools

import (
	"context"
	"time"

	// Redis 6.0及以下版本：选择Go-redis v8.0及以下版本。
	"github.com/go-redis/redis/v8"
	redsync "github.com/go-redsync/redsync/v4"
	"github.com/go-redsync/redsync/v4/redis/goredis/v8"
	// Redis 7.0及以上版本：选择Go-redis v9.0及以上版本。
	// "github.com/go-redsync/redsync/v4/redis/goredis/v9"
	// "github.com/redis/go-redis/v9"
)

/*
 +----------------------------------------------------------------------
 + Title        : redis 缓存
 + Author       : huwl
 + Version      : 1.0.0
 + Initial-Time : 2021-09-22
 + Last-time    : 这个文件最后修改的时间 + 修改人的名称
 + Desc         : redis 缓存 文档地址【https://redis.uptrace.dev/zh/guide/go-redis.html】
 +----------------------------------------------------------------------
*/

// var RedisDBClient *redis.Client
// var RedisClusterClient *redis.ClusterClient
// var RedisMode string
// var RsPool *redsync.Redsync

var ctx = context.Background()

// redis 配置信息
type RedisConf struct {
	Mode   string `yaml:"mode" json:"mode"`
	Single struct {
		Host     string `yaml:"host" json:"host"`
		Password string `yaml:"password" json:"password"`
		Db       int64  `yaml:"db" json:"db"`
	}

	Replication struct {
		Host     string `yaml:"host" json:"host"`
		Password string `yaml:"password" json:"password"`
		Db       int64  `yaml:"db" json:"db"`
	}

	Sentinel struct {
		Host       []string `yaml:"host" json:"host"`
		Password   string   `yaml:"password" json:"password"`
		MasterName string   `yaml:"master_name" json:"master_name"`
		Db         int64    `yaml:"db" json:"db"`
	}

	Cluster struct {
		Host     []string `yaml:"host" json:"host"`
		Password string   `yaml:"password" json:"password"`
		Db       int64    `yaml:"db" json:"db"`
	}
}

// func init() {
// 	InitRedisConnect()
// }

// 初始化 redis 连接
// func InitRedisConnect() {
// 	// +++++++++++++++++ 使用本地配置方式开始 +++++++++++++++++
// 	// // 读取 redis 配置
// 	// cfg, err := GetConfig("redis", "yml")
// 	// if err != nil {
// 	// 	fmt.Println("error = ", err.Error())
// 	// 	return
// 	// }

// 	// //模式【single、replication、sentinel、cluster】
// 	// mode := cfg.GetString("mode")
// 	// +++++++++++++++++ 使用本地配置方式结束 +++++++++++++++++

// 	// +++++++++++++++++ 使用配置中心方式开始 +++++++++++++++++
// 	var err error
// 	redisConf := &RedisConf{}
// 	InitConfigCenter(RedisConfigCenter, redisConf)
// 	mode := redisConf.Mode
// 	// +++++++++++++++++ 使用配置中心方式结束 +++++++++++++++++
// 	RedisMode = mode

// 	//连接redis
// 	if mode == "single" { // 单机版
// 		RedisDBClient = redis.NewClient(&redis.Options{
// 			// 本地配置文件模式
// 			// Addr:     cfg.GetString(Env + "." + mode + ".host"),
// 			// Password: cfg.GetString(Env + "." + mode + ".password"),
// 			// DB:       cfg.GetInt(Env + "." + mode + ".db"),

// 			// nacos配置中心模式
// 			Addr:     redisConf.Single.Host,
// 			Password: redisConf.Single.Password,
// 			DB:       int(redisConf.Single.Db),
// 		})
// 		_, err = RedisDBClient.Ping(ctx).Result()
// 	} else if mode == "sentinel" { // 哨兵版
// 		RedisDBClient = redis.NewFailoverClient(&redis.FailoverOptions{
// 			// 本地配置文件模式
// 			// MasterName: cfg.GetStringSlice(Env + "." + mode + ".master_name"),
// 			// SentinelAddrs: cfg.GetStringSlice(Env + "." + mode + ".host"),
// 			// Password:      cfg.GetString(Env + "." + mode + ".password"),
// 			// DB:            cfg.GetInt(Env + "." + mode + ".db"),

// 			// nacos配置中心模式
// 			MasterName:    redisConf.Sentinel.MasterName,
// 			SentinelAddrs: redisConf.Sentinel.Host,
// 			Password:      redisConf.Sentinel.Password,
// 			DB:            int(redisConf.Sentinel.Db),
// 		})
// 		_, err = RedisDBClient.Ping(ctx).Result()
// 	} else if mode == "cluster" { // 分片集群版
// 		RedisClusterClient = redis.NewClusterClient(&redis.ClusterOptions{
// 			// 本地配置文件模式
// 			// Addrs:    cfg.GetStringSlice(Env + "." + mode + ".host"),
// 			// Password: cfg.GetString(Env + "." + mode + ".password"),

// 			// nacos配置中心模式
// 			Addrs:    redisConf.Cluster.Host,
// 			Password: redisConf.Cluster.Password,
// 		})

// 		_, err = RedisClusterClient.Ping(ctx).Result()
// 	}

// 	pool := goredis.NewPool(RedisDBClient)
// 	RsPool = redsync.New(pool)

// 	if err != nil {
// 		log.Fatalf("failed to redis client: %v", err)
// 	} else {
// 		log.Println("redis client success ^_^^_^^_^")
// 	}
// }

type RedisInstance struct {
	redisDBClient      *redis.Client
	redisClusterClient *redis.ClusterClient
	redisMode          string
	RsPool             *redsync.Redsync
}

/**
 * 创建 redis 实例
 *
 * @author huwl
 * @date 2025/08/10 10:38:40
 */
func NewRedisInstance() (*RedisInstance, error) {
	// +++++++++++++++++ 使用本地配置方式开始 +++++++++++++++++
	// //读取 redis 配置
	// cfg, err := GetConfig("redis", "yml")
	// if err != nil {
	// 	panic(err.Error())
	// }

	// //模式【single、replication、sentinel、cluster】
	// mode := cfg.GetString("mode")
	// +++++++++++++++++ 使用本地配置方式结束 +++++++++++++++++

	// +++++++++++++++++ 使用nacos配置方式开始 ++++++++++++++++
	var err error
	// 读取 redis 配置
	redisConf := &RedisConf{}
	InitConfigCenter(RedisConfigCenter, redisConf)
	mode := redisConf.Mode
	// +++++++++++++++++ 使用nacos配置方式结束 ++++++++++++++++

	ri := &RedisInstance{
		redisMode: mode,
	}

	//连接redis
	if mode == "single" { // 单机版
		ri.redisDBClient = redis.NewClient(&redis.Options{
			// 本地配置文件模式
			// Addr:     cfg.GetString(Env + "." + mode + ".host"),
			// Password: cfg.GetString(Env + "." + mode + ".password"),
			// DB:       cfg.GetInt(Env + "." + mode + ".db"),

			// nacos配置中心模式
			Addr:     redisConf.Single.Host,
			Password: redisConf.Single.Password,
			DB:       int(redisConf.Single.Db),
		})
		_, err = ri.redisDBClient.Ping(ctx).Result()

	} else if mode == "sentinel" { // 哨兵版
		ri.redisDBClient = redis.NewFailoverClient(&redis.FailoverOptions{

			// 本地配置文件模式
			// MasterName: cfg.GetString(Env + "." + mode + ".master_name"),
			// SentinelAddrs: cfg.GetStringSlice(Env + "." + mode + ".host"),
			// Password:      cfg.GetString(Env + "." + mode + ".password"),
			// DB:            cfg.GetInt(Env + "." + mode + ".db"),

			// nacos配置中心模式
			MasterName:    redisConf.Sentinel.MasterName,
			SentinelAddrs: redisConf.Sentinel.Host,
			Password:      redisConf.Sentinel.Password,
			DB:            int(redisConf.Sentinel.Db),
		})
		_, err = ri.redisDBClient.Ping(ctx).Result()

	} else if mode == "cluster" { // 分片集群版
		ri.redisClusterClient = redis.NewClusterClient(&redis.ClusterOptions{
			// 本地配置文件模式
			// Addrs:    cfg.GetStringSlice(Env + "." + mode + ".host"),
			// Password: cfg.GetString(Env + "." + mode + ".password"),

			// nacos配置中心模式
			Addrs:    redisConf.Cluster.Host,
			Password: redisConf.Cluster.Password,
		})

		_, err = ri.redisClusterClient.Ping(ctx).Result()
	}

	pool := goredis.NewPool(ri.redisDBClient)
	ri.RsPool = redsync.New(pool)

	return ri, err
}

/**
 * 设置值
 *
 * @param string key --------------------------------------必传
 * @param []interface{} value -----------------------------必传
 * @param time.Duration expiration ------------------------必传
 * @return error
 * @author huwl
 */
func (in *RedisInstance) RedisSet(key string, value interface{}, expiration time.Duration) error {
	if in.redisMode == "single" || in.redisMode == "sentinel" {
		return in.redisDBClient.Set(ctx, key, value, expiration).Err()
	}

	return in.redisClusterClient.Set(ctx, key, value, expiration).Err()
}

/**
 * 获取值
 *
 * @param string key --------------------------------------必传
 * @return string error
 * @author huwl
 */
func (in *RedisInstance) RedisGet(key string) (string, error) {
	if in.redisMode == "single" || in.redisMode == "sentinel" {
		return in.redisDBClient.Get(ctx, key).Result()
	}

	return in.redisClusterClient.Get(ctx, key).Result()
}

/**
 * 删除
 *
 * @param string key --------------------------------------必传
 * @return error
 * @author huwl
 */
func (in *RedisInstance) RedisDel(key string) error {
	if in.redisMode == "single" || in.redisMode == "sentinel" {
		return in.redisDBClient.Del(ctx, key).Err()
	}

	return in.redisClusterClient.Del(ctx, key).Err()
}

/**
 * 左进列表
 *
 * @param string key --------------------------------------必传
 * @param []interface{} values ----------------------------必传
 * @return string error
 * @author huwl
 */
func (in *RedisInstance) RedisLpush(key string, values []interface{}) error {
	if in.redisMode == "single" || in.redisMode == "sentinel" {
		return in.redisDBClient.LPush(ctx, key, values).Err()
	}

	return in.redisClusterClient.LPush(ctx, key, values).Err()
}

/**
 * 左出列表
 *
 * @param string key --------------------------------------必传
 * @return error
 * @author huwl
 */
func (in *RedisInstance) RedisLpop(key string) (string, error) {
	if in.redisMode == "single" || in.redisMode == "sentinel" {
		return in.redisDBClient.LPop(ctx, key).Result()
	}

	return in.redisClusterClient.LPop(ctx, key).Result()
}

/**
 * 右进列表
 *
 * @param string key --------------------------------------必传
 * @param []interface{} values ----------------------------必传
 * @return error
 * @author huwl
 */
func (in *RedisInstance) RedisRpush(key string, values []interface{}) error {
	if in.redisMode == "single" || in.redisMode == "sentinel" {
		return in.redisDBClient.RPush(ctx, key, values...).Err()
	}

	return in.redisClusterClient.RPush(ctx, key, values...).Err()
}

/**
 * 右进列表
 *
 * @param string key -----------------------------------------必传
 * @return string error
 * @author huwl
 */
func (in *RedisInstance) RedisRpop(key string) (string, error) {
	if in.redisMode == "single" || in.redisMode == "sentinel" {
		return in.redisDBClient.RPop(ctx, key).Result()
	}

	return in.redisClusterClient.RPop(ctx, key).Result()
}

/**
 * geoadd
 *
 * @param string key -----------------------------------------必传
 * @param string name ----------------------------------------必传
 * @param float64 longitude ----------------------------------必传
 * @param float64 latitude -----------------------------------必传
 * @return string error
 * @author huwl
 */
func (in *RedisInstance) RedisGeoadd(key, name string, longitude, latitude float64) error {
	if in.redisMode == "single" || in.redisMode == "sentinel" {
		return in.redisDBClient.GeoAdd(ctx, key, &redis.GeoLocation{Name: name, Longitude: longitude, Latitude: latitude}).Err()
	}

	return in.redisClusterClient.GeoAdd(ctx, key, &redis.GeoLocation{Name: name, Longitude: longitude, Latitude: latitude}).Err()
}

/**
 * geodist
 *
 * @param string key -----------------------------------------必传
 * @param string member1 -------------------------------------必传
 * @param string member2 -------------------------------------必传
 * @param string unit ----------------------------------------必传
 * @return string error
 * @author huwl
 */
func (in *RedisInstance) RedisGeodist(key, member1, member2, unit string) (float64, error) {
	if in.redisMode == "single" || in.redisMode == "sentinel" {
		return in.redisDBClient.GeoDist(ctx, key, member1, member2, unit).Result()
	}

	return in.redisClusterClient.GeoDist(ctx, key, member1, member2, unit).Result()
}

/**
 * georadius
 *
 * @param string key --------------------------------------必传
 * @param float64 longitude -------------------------------必传
 * @param float64 latitude --------------------------------必传
 * @param float64 radius ----------------------------------必传
 * @param string unit -------------------------------------必传
 * @param withCoord bool ----------------------------------必传
 * @param withDist bool -----------------------------------必传
 * @param string sort -------------------------------------必传
 * @return string error
 * @author huwl
 */
func (in *RedisInstance) RedisGeoradius(key string, longitude, latitude, radius float64, unit string, withCoord, withDist bool, sort string) ([]redis.GeoLocation, error) {
	geoRadiusQuery := &redis.GeoRadiusQuery{
		Radius:    radius,
		Unit:      unit,
		WithCoord: withCoord,
		WithDist:  withDist,
		Sort:      sort,
		// 	WithCoord   bool
		// WithDist    bool
		// WithGeoHash bool
		// Count       int
		// // Can be ASC or DESC. Default is no sort order.
		// Sort      string
		// Store     string
		// StoreDist string
	}
	if in.redisMode == "single" || in.redisMode == "sentinel" {
		return in.redisDBClient.GeoRadius(ctx, key, longitude, latitude, geoRadiusQuery).Result()
	}

	return in.redisClusterClient.GeoRadius(ctx, key, longitude, latitude, geoRadiusQuery).Result()
}

/**
 * 删除geo位置(geo本质就是有序集合，因此可以使用有序集合的方式删除)
 *
 * @param string key -----------------------------------------必传
 * @param []interface{} members ------------------------------非必传
 * @return error
 * @author huwl
 */
func (in *RedisInstance) RedisGeoremove(key string, members ...interface{}) error {
	if in.redisMode == "single" || in.redisMode == "sentinel" {
		return in.redisDBClient.ZRem(ctx, key, members).Err()
	}

	return in.redisClusterClient.ZRem(ctx, key, members).Err()
}

/**
 * 有序集合删除成员
 *
 * @param string key -----------------------------------------必传
 * @param []interface{} members ------------------------------非必传
 * @return error
 * @author huwl
 */
func (in *RedisInstance) RedisZrem(key string, members ...interface{}) error {
	if in.redisMode == "single" || in.redisMode == "sentinel" {
		return in.redisDBClient.ZRem(ctx, key, members).Err()
	}

	return in.redisClusterClient.ZRem(ctx, key, members).Err()
}

// 待续。。。
